﻿using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.CompilerServices;

namespace Microsoft.Coding4Fun.TweetCraft.Twitter
{
    public class TwitterUserPictureService<TDownloadClient, TUserPictureConverter> : ITwitterUserPictureService where TDownloadClient : DownloadClient, new()
                                                                                                                where TUserPictureConverter : UserPictureConverter, new()
    {
        private const string PictureDirectoryName = "TweetCraft";

        private const string TgaExtension = ".tga";
        private const string TempFileNameExtension = ".tmp";

        private static readonly TUserPictureConverter UserPictureConverter = new TUserPictureConverter();
        private static readonly TDownloadClient DownloadClient = new TDownloadClient();

        /// <summary>
        /// Initializes a new instance of the <see cref="TwitterUserPictureService{TDownloadClient,TUserPictureConverter}"/> class.
        /// </summary>
        public TwitterUserPictureService()
        {
            // Initialize defaults
            this.UserPictureDirectory = Path.Combine(Path.GetTempPath(), PictureDirectoryName);
        }

        /// <summary>
        /// Gets or sets the folder where user pictures should be saved after converted.
        /// </summary>
        public string UserPictureDirectory { get; set; }

        /// <summary>
        /// Gets the path to a user picture based on the user's id.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <returns>
        /// A <see cref="string"/> containing the path to the user's picture. Can be null.
        /// </returns>
        public string GetUserPicturePath(User user)
        {
            if (user == null)
                throw new ArgumentNullException("user");

            // Determine whether the user has a picture at all
            if (user.ImageUrl == null)
                return null;

            // Combine the local path to the user's picture
            string userPicturePath = Path.Combine(this.UserPictureDirectory, user.ScreenName + TgaExtension);

            // Immediately return picture path, if it exists
            if (File.Exists(userPicturePath))
            {
                Trace.TraceInformation("User picture already available, no download and conversion is necessary.");
                return userPicturePath;
            }

            // Perform downloading and converting of user picture
            if (CreateUserPicture(user, userPicturePath))
                return userPicturePath;

            // Couldn't get it in place, return null
            return null;
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        private static bool CreateUserPicture(User user, string picturePath)
        {
            if (user == null)
                throw new ArgumentNullException("user");
            if (picturePath == null)
                throw new ArgumentNullException("picturePath");

            string pictureDirectoryPath = Path.GetDirectoryName(picturePath);

            // If the directory for user pictures does not exists, create it
            if (!Directory.Exists(pictureDirectoryPath))
                Directory.CreateDirectory(pictureDirectoryPath);

            using (TraceScope downloadScope = TraceScope.Information("Downloading and converting {0}'s user picture...", user.ScreenName))
            {
                // Generate a temporary filename with the correct extension
                string tempFileName = Path.GetTempFileName().Replace(TempFileNameExtension, Path.GetExtension(user.ImageUrl.OriginalString));

                try
                {
                    Trace.TraceInformation("Downloading user picture from {0}...", user.ImageUrl);

                    // Download to temporary file before loading and enlarging it
                    DownloadClient.DownloadFile(user.ImageUrl, tempFileName);

                    Trace.TraceInformation("Downloaded user picture, starting conversion...");

                    // Perform the conversion using the user picture converter
                    return UserPictureConverter.Convert(tempFileName, picturePath);
                }
                catch (WebException exception)
                {
                    Trace.TraceWarning("Could not download user picture: {0}", exception.Message);

                    // Uncomment the line below and add (WebException exception) to the catch clause
                    // to report any error that occurs during downloading of the user pictures.

                    // this.OnError(exception);
                    return false;
                }
                finally
                {
                    downloadScope.Complete("Download and conversion finished.");
                }
            }
        }

    }
}
